home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Deutsche Edition 1
/
Deutsche Edition 1.iso
/
amok
/
amok_lha
/
amok24.lha
/
TurboFiles
/
TurboFiles.mod
< prev
next >
Wrap
Text File
|
1993-08-15
|
18KB
|
601 lines
(**********************************************************************
:Program. TurboFiles.mod
:Contents. Replacement of the AM-FileSystem
:Author. Stefan Salewski
:Copyright. Public Domain
:Language. Modula-2 with INLINE-Assembler-Code
:Imports. Assembler2
:Translator. M2Amiga AMSoft V3.2d
:History. V1.0 1.Jul.1989
:Address. Stolper Weg 3, D-2160 Stade
**********************************************************************)
IMPLEMENTATION MODULE TurboFiles;
(*
Created: 4/89
Changed: 12.5.89/13.5.89/20.5.89/28.5.89/31.5.89/9.6.89/13.6.89/
15.6.89/21.6.89/1.7.89 by
Stefan Salewski
Stolper Weg 3
D-2160 Stade
*)
IMPORT Dos;
FROM Assembler2 IMPORT MinLongInt,MaxLongInt,MaxCard;
FROM SYSTEM IMPORT ADDRESS,ADR,BYTE,CAST,INLINE;
FROM Arts IMPORT TermProcedure,CurrentLevel,Assert;
FROM Exec IMPORT AllocMem,CopyMem,FreeMem,MemReqs,MemReqSet,UByte;
FROM RandomNumber IMPORT PutSeed,RND;
FROM Str IMPORT Length;
VAR
fileList,dummyFile:FilePtr;
DosBase:ADDRESS;
startLevel:INTEGER; (* only for Loader/Debugger *)
PROCEDURE Lookup(VAR f:FilePtr;VAR name:ARRAY OF CHAR;
bufferSize:CARDINAL;mode:AccessMode):TurboResult;
VAR
buf:ADDRESS;
l:LONGINT;
BEGIN
f:=AllocMem(SIZE(File),MemReqSet{public});
IF f=NIL THEN
RETURN outOfMem
END;
bufferSize:=MaxCard(bufferSize,1);
buf:=AllocMem(bufferSize,MemReqSet{public});
IF buf=NIL THEN
FreeMem(f,SIZE(File));
RETURN outOfMem
END;
f^.fhPtr:=Dos.Open(ADR(name),mode);
IF f^.fhPtr=NIL THEN
FreeMem(f,SIZE(File));
FreeMem(buf,bufferSize);
f:=NIL;
RETURN openError;
ELSE
f^.base:=buf;
f^.dosBase:=DosBase;
(*f^.writeBase=f^.act will be initialized by the first call
of WriteBytes *)
f^.writeTop:=f^.base;
f^.filePos:=0;
f^.top:=f^.base+LONGINT(bufferSize);
f^.act:=f^.base;
f^.readTop:=f^.base;
f^.res:=done;
IF mode=NewFile THEN
f^.startLength:=0
ELSE
l:=Dos.Seek(f^.fhPtr,0,Dos.end);
f^.startLength:=Dos.Seek(f^.fhPtr,0,Dos.beginning)
END;
f^.next:=fileList;
fileList:=f;
RETURN done;
END;
END Lookup;
PROCEDURE CloseFile(VAR f:FilePtr);
VAR
l:LONGINT;
currentFile,prevFile:FilePtr;
BEGIN
IF f^.writeTop>f^.base THEN
l:=Dos.Seek(f^.fhPtr,f^.writeBase-f^.readTop,Dos.current);
l:=Dos.Write(f^.fhPtr,f^.writeBase,f^.writeTop-f^.writeBase);
END;
Dos.Close(f^.fhPtr);
IF f=fileList THEN
fileList:=f^.next
ELSE
currentFile:=fileList;
WHILE (currentFile#f) AND (currentFile#NIL) DO
prevFile:=currentFile;
currentFile:=currentFile^.next
END;
Assert(currentFile#NIL,ADR('TurboFiles.Close: File not Found'));
prevFile^.next:=currentFile^.next
END;
FreeMem(f^.base,f^.top-f^.base);
FreeMem(f,SIZE(f));
f:=NIL;
END CloseFile;
PROCEDURE DeleteFile(VAR fileName:ARRAY OF CHAR):BOOLEAN;
BEGIN
RETURN Dos.DeleteFile(ADR(fileName));
END DeleteFile;
PROCEDURE ReadBytes(f:FilePtr;adr:ADDRESS;
len:LONGINT;VAR actual:LONGINT);
VAR
toRead,l:LONGINT;
BEGIN
actual:=0;
IF (f^.res#done) OR (len<=0) THEN
RETURN
END;
LOOP
IF f^.act>=f^.readTop THEN
IF f^.writeTop>f^.base THEN
l:=Dos.Seek(f^.fhPtr,f^.writeBase-f^.readTop,Dos.current);
toRead:=f^.writeTop-f^.writeBase;
l:=Dos.Write(f^.fhPtr,f^.writeBase,toRead);
IF l<toRead THEN
f^.res:=writeError;
EXIT
END;
toRead:=f^.act-f^.writeTop;
IF toRead#0 THEN
l:=Dos.Seek(f^.fhPtr,toRead,Dos.current)
END;
f^.filePos:=f^.filePos+f^.act-f^.readTop;
f^.writeTop:=f^.base;
END;
l:=Dos.Read(f^.fhPtr,f^.base,f^.top-f^.base);
INC(f^.filePos,l);
IF l=0 THEN
f^.res:=endOfFile;
EXIT
END;
f^.act:=f^.base;
f^.readTop:=f^.base+l;
END;
toRead:=MinLongInt(f^.readTop-f^.act,len);
CopyMem(f^.act,adr,toRead);
INC(f^.act,toRead);
INC(adr,toRead);
DEC(len,toRead);
INC(actual,toRead);
IF len=0 THEN
EXIT
END
END;
END ReadBytes;
PROCEDURE TurboRead(f{10}:FilePtr;adr{6}:ADDRESS;
len{7}:LONGINT;VAR actual{11}:LONGINT);
(*$E-*)
BEGIN
INLINE(
04293H,00C2AH,00001H,00028H,06600H,000C8H,04A87H,06F00H,
000C2H,0282AH,00018H,0B8AAH,0001CH,06D7CH,02A2AH,00008H,
0BAAAH,00024H,0674EH,0242AH,00020H,094AAH,0001CH,07600H,
0222AH,00000H,02C6AH,00004H,04EAEH,0FFBEH,0262AH,00024H,
096AAH,00020H,0222AH,00000H,0242AH,00020H,04EAEH,0FFD0H,
0B680H,06670H,02404H,094AAH,00024H,0670AH,0222AH,00000H,
07600H,04EAEH,0FFBEH,02004H,090AAH,0001CH,0D1AAH,00010H,
02545H,00024H,0262AH,0000CH,09685H,0222AH,00000H,02405H,
02C6AH,00004H,04EAEH,0FFD6H,04A80H,06740H,0D1AAH,00010H,
02805H,0D085H,02540H,0001CH,0202AH,0001CH,09084H,0B087H,
06F02H,02007H,0D193H,09E80H,05380H,02044H,02246H,012D8H,
051C8H,0FFFCH,02808H,02C09H,04A87H,06600H,0FF5AH,02544H,
00018H,04E75H,0157CH,00005H,00028H,06006H,0157CH,00007H,
00028H,02544H,00018H,04E75H);
END TurboRead;
PROCEDURE WriteBytes(f:FilePtr;adr:ADDRESS;len:LONGINT);
VAR
toWrite,l:LONGINT;
BEGIN
IF (f^.res#done) OR (len<=0) THEN
RETURN
END;
IF f^.writeTop=f^.base THEN
f^.writeBase:=f^.act
END;
LOOP
IF f^.act=f^.top THEN
IF f^.writeTop>f^.base THEN
l:=Dos.Seek(f^.fhPtr,f^.writeBase-f^.readTop,Dos.current);
toWrite:=f^.writeTop-f^.writeBase;
l:=Dos.Write(f^.fhPtr,f^.writeBase,toWrite);
IF l<toWrite THEN
f^.res:=writeError;
EXIT
END;
toWrite:=f^.act-f^.writeTop;
IF toWrite#0 THEN
l:=Dos.Seek(f^.fhPtr,toWrite,Dos.current)
END;
f^.filePos:=f^.filePos+f^.act-f^.readTop;
f^.writeTop:=f^.base;
END;
f^.writeBase:=f^.base;
f^.act:=f^.base;
f^.readTop:=f^.base;
END;
toWrite:=MinLongInt(f^.top-f^.act,len);
CopyMem(adr,f^.act,toWrite);
INC(adr,toWrite);
INC(f^.act,toWrite);
DEC(len,toWrite);
f^.writeTop:=f^.act;
IF len=0 THEN
EXIT
END
END;
END WriteBytes;
PROCEDURE TurboWrite(f{10}:FilePtr;adr{11}:ADDRESS;len{7}:LONGINT);
(*$E-*)
BEGIN
INLINE(
00C2AH,00001H,00028H,06600H,000AEH,04A87H,06F00H,000A8H,
02C2AH,0000CH,02A2AH,00008H,0282AH,00018H,0BAAAH,00024H,
06604H,02544H,00020H,0BC84H,06E5EH,0BAAAH,00024H,0674EH,
0242AH,00020H,094AAH,0001CH,07600H,0222AH,00000H,02C6AH,
00004H,04EAEH,0FFBEH,0262AH,00024H,096AAH,00020H,0222AH,
00000H,0242AH,00020H,04EAEH,0FFD0H,0B680H,06652H,02404H,
094AAH,00024H,0670AH,0222AH,00000H,07600H,04EAEH,0FFBEH,
02004H,090AAH,0001CH,0D1AAH,00010H,02545H,00024H,02545H,
00020H,02805H,02545H,0001CH,02006H,09084H,0B087H,06F02H,
02007H,09E80H,05380H,02044H,010DBH,051C8H,0FFFCH,02808H,
02548H,00024H,04A87H,06600H,0FF7EH,02544H,00018H,04E75H,
0157CH,00005H,00028H,02544H,00018H,04E75H);
END TurboWrite;
PROCEDURE ReadChar(f:FilePtr;VAR ch:CHAR);
VAR
len:LONGINT;
BEGIN
TurboRead(f,ADR(ch),1,len)
END ReadChar;
PROCEDURE WriteChar(f:FilePtr;ch:CHAR);
BEGIN
TurboWrite(f,ADR(ch),1)
END WriteChar;
PROCEDURE ReadByteBlock(f:FilePtr;VAR block:ARRAY OF BYTE);
VAR
len:LONGINT;
BEGIN
TurboRead(f,ADR(block),SIZE(block),len)
END ReadByteBlock;
PROCEDURE WriteByteBlock(f:FilePtr;VAR block:ARRAY OF BYTE);
BEGIN
TurboWrite(f,ADR(block),SIZE(block))
END WriteByteBlock;
PROCEDURE GetPos(f:FilePtr):LONGINT;
BEGIN
IF f^.res#done THEN
RETURN -1
ELSE
RETURN f^.filePos+f^.act-f^.readTop
END
END GetPos;
(*$F-*)
PROCEDURE TurboGetPos(f{11}:FilePtr):LONGINT;
(*$E-*)
BEGIN
INLINE(
00C2BH,00001H,00028H,0660EH,0202BH,00010H,0D0ABH,00018H,
090ABH,0001CH,04E75H,070FFH,04E75H);
END TurboGetPos;(*$F=*)
PROCEDURE SetPos(f:FilePtr;offset:LONGINT;mode:SetPosMode):BOOLEAN;
VAR
l,newPos,bufTop,getPos:ADDRESS;
BEGIN
IF f^.res#done THEN
RETURN FALSE
END;
f^.startLength:=FileLength(f);
getPos:=f^.filePos+f^.act-f^.readTop;
bufTop:=MaxLongInt(f^.readTop,f^.act);
IF mode=beginning THEN
offset:=ABS(offset)-getPos
ELSIF mode=end THEN
offset:=f^.startLength-getPos-ABS(offset)
END;
newPos:=f^.act+offset;
IF (newPos>=f^.base) AND (newPos<bufTop) THEN
f^.act:=newPos;
RETURN TRUE
ELSE
newPos:=getPos+offset;
IF (newPos<0) OR (newPos>f^.startLength) THEN
f^.res:=seekError;
RETURN FALSE
ELSE
IF f^.writeTop>f^.base THEN
l:=Dos.Seek(f^.fhPtr,f^.writeBase-f^.readTop,Dos.current);
getPos:=f^.writeTop-f^.writeBase;
l:=Dos.Write(f^.fhPtr,f^.writeBase,getPos);
IF l<getPos THEN
f^.res:=writeError;
RETURN FALSE
END;
f^.writeTop:=f^.base
END;
l:=Dos.Seek(f^.fhPtr,newPos,Dos.beginning);
f^.filePos:=newPos;
f^.act:=f^.base;
f^.readTop:=f^.base;
RETURN TRUE;
END;
END;
END SetPos;
(*$F-*)
PROCEDURE TurboSetPos(f{10}:FilePtr;offset{6}:LONGINT;
mode{7}:SetPosMode):BOOLEAN;
(*$E-*)
BEGIN
INLINE(
00C2AH,00001H,00028H,06600H,000D6H,0266AH,00008H,0222AH,
00018H,0242AH,00010H,0D481H,094AAH,0001CH,02A2AH,00014H,
0BA82H,06C06H,02A02H,02545H,00014H,0262AH,0001CH,0B681H,
06C02H,02601H,00C07H,00001H,06716H,04A86H,06A02H,04486H,
00C07H,00000H,06604H,09C82H,06006H,04486H,0DC85H,09C82H,
02801H,0D886H,0B8AAH,00008H,06D0CH,0B883H,06C08H,02544H,
00018H,070FFH,04E75H,02802H,0D886H,04A84H,06B6AH,0B885H,
06E66H,0B7EAH,00024H,06732H,0222AH,00000H,0242AH,00020H,
094AAH,0001CH,07600H,02C6AH,00004H,04EAEH,0FFBEH,0222AH,
00000H,0242AH,00020H,0262AH,00024H,096AAH,00020H,04EAEH,
0FFD0H,0B680H,0662AH,0254BH,00024H,0222AH,00000H,02404H,
076FFH,02C6AH,00004H,04EAEH,0FFBEH,04A80H,06B1AH,02544H,
00010H,0254BH,00018H,0254BH,0001CH,01038H,0FFFFH,04E75H,
0157CH,00005H,00028H,06006H,0157CH,00006H,00028H,07000H,
04E75H);
END TurboSetPos;(*$F=*)
PROCEDURE FileLength(f:FilePtr):LONGINT;
VAR
getPos:LONGINT;
BEGIN
IF f^.res#done THEN
RETURN -1
END;
getPos:=f^.filePos+f^.act-f^.readTop;
RETURN MaxLongInt(f^.startLength,getPos);
END FileLength;
(*$F-*)
PROCEDURE TurboFileLength(f{11}:FilePtr):LONGINT;
(*$E-*)
BEGIN
INLINE(
00C2BH,00001H,00028H,06618H,0202BH,00010H,0D0ABH,00018H,
090ABH,0001CH,0222BH,00014H,0B081H,06C06H,02001H,04E75H,
070FFH,04E75H);
END TurboFileLength;(*$F=*)
PROCEDURE Search(f:FilePtr;VAR str:ARRAY OF BYTE;len:LONGINT):LONGINT;
VAR
i,act:LONGINT;
b:CHAR;
BEGIN
IF (len>SIZE(str)) OR (len<=0) THEN
len:=SIZE(str)
END;
DEC(len);
LOOP
i:=0;
LOOP
TurboRead(f,ADR(b),1,act);
IF (b#CAST(CHAR,str[i])) OR (i=len) THEN
EXIT
END;
INC(i);
END;
IF (CAST(CHAR,str[i])=b) AND TurboSetPos(f,-i-1,current) THEN
RETURN TurboGetPos(f)
ELSIF NOT TurboSetPos(f,-i,current) THEN
RETURN -1
END;
END;
END Search;
PROCEDURE Code(fileName,codeWord:ARRAY OF CHAR;decode:BOOLEAN):BOOLEAN;
CONST
Mult=2;
CodeStringSize=255;
TYPE
Long=[0..CodeStringSize];
CodeString=ARRAY Long OF UByte;
PROCEDURE Permute(VAR index,code:CodeString;len:INTEGER);
VAR
qsum:LONGINT;
i,try:INTEGER;
free:ARRAY Long OF BOOLEAN;
BEGIN
(* generating a permutation of the numbers 0..(len-1).
This permutation depends on code and will be
stored in index
*)
qsum:=0;
FOR i:=0 TO len-1 DO
INC(qsum,code[i])
END;
PutSeed(qsum);
FOR i:=0 TO len-1 DO
free[i]:=TRUE;
END;
i:=0;
REPEAT
try:=RND(len);
IF free[try] THEN
index[i]:=try;
free[try]:=FALSE;
INC(i);
END;
UNTIL i=len;
END Permute;
VAR
act,i:LONGINT;
cWLen:LONGINT;
fPtr:FilePtr;
eof:BOOLEAN;
code,readPuffer,writePuffer,index:CodeString;
BEGIN
cWLen:=MinLongInt(Length(codeWord),CodeStringSize);
CopyMem(ADR(codeWord),ADR(code),cWLen+1);
IF cWLen=0 THEN
RETURN FALSE
END;
IF Lookup(fPtr,fileName,512,ReadWrite)=done THEN
WHILE cWLen*2<CodeStringSize DO
CopyMem(ADR(code),ADR(code)+cWLen,cWLen+1);
INC(cWLen,cWLen);
END;
Permute(index,code,cWLen);
FOR i:=0 TO cWLen-1 DO
(*$V-*)
code[i]:=code[i]*Mult;
(*$V=*)
END;
eof:=FALSE;
WHILE NOT eof DO
TurboRead(fPtr,ADR(readPuffer),cWLen,act);
IF act<cWLen THEN
eof:=TRUE;
fPtr^.res:=done; (* So I can write to the file again *)
Permute(index,code,act)
END;
IF NOT decode THEN
FOR i:=0 TO act-1 DO
(*$V-*)
INC(readPuffer[i],code[i])
(*$V=*)
END;
FOR i:=0 TO act-1 DO
writePuffer[i]:=readPuffer[index[i]]
END;
ELSE
FOR i:=0 TO act-1 DO
writePuffer[index[i]]:=readPuffer[i]
END;
FOR i:=0 TO act-1 DO
(*$V-*)
DEC(writePuffer[i],code[i])
(*$V=*)
END;
END;
IF TurboSetPos(fPtr,-act,current) THEN END;
TurboWrite(fPtr,ADR(writePuffer),act)
END;
CloseFile(fPtr);
RETURN TRUE
ELSE
RETURN FALSE
END;
END Code;
PROCEDURE Cleanup;
BEGIN
IF CurrentLevel()<=startLevel THEN
WHILE fileList#NIL DO
dummyFile:=fileList;
CloseFile(dummyFile)
END;
END
END Cleanup;
BEGIN
fileList:=NIL;
startLevel:=CurrentLevel();
DosBase:=ADR(Dos);
TermProcedure(Cleanup);
END TurboFiles.mod
(*
Now a short explaination of the datastructures I use:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CONST *** the accessmodes for the File
ReadOnly = Dos.readOnly;
ReadWrite= Dos.readWrite;
NewFile = Dos.newFile;
TYPE
TurboResult=(notOpen,done,notdone,openError,readError,writeError,
seekError,endOfFile,outOfMem,tooManyFiles);
SetPosMode=(beginning,current,end);
AccessMode=[ReadWrite..NewFile];
FilePtr=POINTER TO File;
File=RECORD
fhPtr:Dos.FileHandlePtr;
dosBase:ADDRESS;
base:ADDRESS;
top:ADDRESS;
filePos:LONGINT;
startLength:LONGINT;
act:ADDRESS;
readTop:ADDRESS;
writeBase:ADDRESS;
writeTop:ADDRESS;
res:TurboResult;
next:FilePtr;
END;
***
-fpPtr is the FileHandlePtr of the Dos-File.
-dosBase is the basic-address of the Dos-functions.
This dosBase I need only to call Dos-Functions from Assembler.
-base is the base of my buffer,
-top is the top of my buffer. The size of the buffer=top-base.
-filePos is the current position in the Dos-File,
(=Dos.Seek(fhPtr,Dos.current,0)).
-startLength is the Size of the Dos-file when I open it.
Notice: I change startLength, when SetPos is called.
-act is the current position in the buffer. If you call
ReadBytes, the first Byte that you get is the byte at address act.
-readTop is used by ReadBytes. If the buffer is empty, I call
l:=Dos.Read(fhPtr,base,buffersize) to fill it.
Then readTop:=base+l.
Now the part of the buffer from base to readTop contains
defined data.
-writeBase: If the content of the buffer is changed the first
time by WriteBytes at position act, I use writeBase:=act to remember
this position. Later I save not the whole buffer to disk, but
only the bytes from writeBase to writeTop.
-writeTop is the address of the upper byte in the buffer that is
changed by WriteBytes. When WriteBytes terminates, it set
writeTop:=act.
-res is the result of every operation. If any procedure set
res to a value unequal done, then all following procedure-calls
except Close will be ignored.
-next is a pointer to the next open file.
How did it works ?
~~~~~~~~~~~~~~~~~~
top n-1---
.--- b
^ .--- u
read | act .--- f
write | 3--- f
2--- e
1--- r
base 0---
The buffer contains n=top-base bytes. base is the address of the lowest
byte of the buffer, top the address of the highest byte.
act is the current position in the buffer. ReadBytes and WriteBytes
increase act until act=readTop(ReadBytes) or until act=top(WriteBytes).
WriteBytes writes to the buffer, until act=top. Then WriteBytes saved
the changed part of the buffer (the area from writeBase to writeTop)
to disk and sets act:=base.
If act=readTop, then ReadBytes examines if the buffer is changed by
WriteBytes( writeTop>base). If the buffer is changed, then ReadBytes
saved the changed part to disk and fills the buffer again.
readTop shows which part of the buffer is filled with data.
Allways the relation holds:
base <= readTop <= top
Stefan Salewski, 26.5.89
*)